//#define __AVR_ATmega32__ 1

#include <stdlib.h>
#include <avr/io.h>
#include <avr/iom32.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <string.h>

#include <cdefs.h>

#include "uart.h"
#include "twimaster.h"
#include "twi_eeprom.h"

#define UART_BAUD_RATE 115200

char bb_ver[16] = "1.0.12.110611";


// Device Settings


#define DEVICE_ID 0xAE		// The EEPROM's addressing identification byte; see the datasheet.
#define DEVICE_MIN 0		// The EEPROM's start address (usually 0)
#define DEVICE_MAX 32767	// The EEPROM's last byte address; the 256K is acutally 32767 (0x7FFF). See the datasheet for details.

#define SEND_BRAY_CLEAR_START 1
#define SEND_BRAY_CLEAR_CMD 1

uint8_t o_ClearCmds = SEND_BRAY_CLEAR_CMD;
uint8_t DeviceID = DEVICE_ID;

void eeprom_output_section(uint16_t wStart, uint16_t wEnd, uint8_t wHexMode)
{
	uint16_t i, i2=0, NewLine=32;
	uint8_t buff;

	uart_puts_P("\n\rR> READING SECTION OF EEPROM: START[0x");
	uart_puthex_16byte(wStart);
	uart_puts_P("] END[0x");
	uart_puthex_16byte(wEnd);
	uart_puts_P("] HEXMODE[0x");
	uart_puthex_byte(wHexMode);
	uart_puts_P("]\n\rR> OUTPUT:\n\r\n\r RO> ");


	if(wHexMode != 1)
		NewLine = 64;

	for ( i = wStart; i < (wEnd+1); i++ )
	{
		buff = eeprom_rd_byte(DeviceID, i);
		if (wHexMode)
		{
			uart_puts_P("[");
			uart_puthex_byte(buff);
			uart_puts_P("] ");
		} else {
			uart_putc(buff);
			uart_puts_P("`");
		}

		_delay_ms(50);
		i2++;
		if(i2 >= NewLine)
		{
			uart_puts_P(" | [0x");
			uart_puthex_16byte(i);
			uart_puts_P("]\n\r RO> ");
			i2=0;
			_delay_ms(200);
		}

	}

}


int main(void)
{
    unsigned int c;
	uint16_t mainloop, i;
	char buffer[16];
	double i2;
	uint8_t getbyte[255];
	uint8_t ret;
	uint16_t location, currentlocation;
	double dub;

    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

    sei();

	// -- Start with status leds on RED/TWI OFF --//
	SETBIT(DDRD,PD5);
	SETBIT(PORTD,PD5);
	CLEARBIT(DDRD,PD6);
	CLEARBIT(PORTD,PD6);
	// -------------------------------------------//

	#if(SEND_BRAY_CLEAR_START)
	uart_putc(0x04);
	_delay_ms(200);
	#endif

	uart_puts_P("\n\r[ BIG-BOSS v ] SYSTEM IS INITILIZED AND READY [ BRENTBXR ]\n\r");
	uart_puts_P("----------------------------------------------------------\n\r");
	uart_puts_P("Please input a (sub)command...\n\r\n\r");

    for(;;)
    {

        c = uart_getc();
        if ( c & UART_NO_DATA )
        {
        }
        else
        {
			if(o_ClearCmds)
			{
				uart_putc(0x04);
				_delay_ms(200);
			}
			/** --------- @s Error Check ---------- **/
            if ( c & UART_FRAME_ERROR )
            {
                uart_puts_P("XX>> UART Frame Error! ");
				break;
            }
            if ( c & UART_OVERRUN_ERROR )
            {
                uart_puts_P("XX>> UART Overrun Error!");
				break;
            }
            if ( c & UART_BUFFER_OVERFLOW )
            {
                uart_puts_P("XX>> Buffer overflow error!");
				break;
            }
			/** --------- Error Check @e ---------- **/
			uart_puts_P(">> Input Recived: \"");
			uart_putc((unsigned char)c );
			uart_puts_P("\" - Looking up function... \n\r");
			if ( c == (unsigned char)'i')																/// [i]: Initilize TWI Serial Communication.
			{
				uart_puts_P("\n\rINITILIZING 2WIRE SERIAL COMMUNICATION...");
				i2c_init();
				uart_puts_P("\n\rTESTING START (GET ACK): ");
				if(i2c_start(0xAE) == 0)
				{
					uart_puts_P(" OK\n\r>> 2WIRE SERIAL INTERFACE HAS BEEN INITILIZED PROPERLY.");
					SETBIT(DDRD,PD6);
					SETBIT(PORTD,PD6);
					CLEARBIT(DDRD,PD5);
					CLEARBIT(PORTD,PD5);
				}
				else
				{
					uart_puts_P(" FAIL\n\r !> 2WIRE SERIAL INTERFACE HAS FAILED ITS INITILIZATION.");
					SETBIT(DDRD,PD5);
					SETBIT(PORTD,PD5);
					CLEARBIT(DDRD,PD6);
					CLEARBIT(PORTD,PD6);
				}
				uart_puts_P("\n\rDONE");

			}
			else if ( c == (unsigned char)'D')															/// [D]: Dump entire contents of EEPROM in HEX mode.
			{
				location = DEVICE_MIN; //Start location
				currentlocation = 0;
				uart_puts_P("\n\rBEGIN> DUMP ENTIRE CONTENTS OF EEPROM - HEX MODE @ 51b per line\n\rOUT>\n\r");
				for ( mainloop = 1; mainloop < 129; mainloop++ ) {
					location = (255*mainloop);
					//------- READ LOOP -------------//
					DeviceID &= ~(1<<0);
					i2c_start_wait(DeviceID);
					i2c_write((location >> 8));
					i2c_write(location);
					DeviceID |= (1<<0);
					i2c_rep_start(DeviceID);

					for ( i = 0; i < 255; i++ ) {
						getbyte[i] = i2c_readAck();
					}

					i2c_stop();

					//-------- OUTPUT LOOP ----------//

					ret = 0;

					for ( i = 0; i < 255; i++ )
					{
						ret++;
						uart_puts_P(" ");
						uart_puthex_byte(getbyte[i]);
						getbyte[i] = 0;
						if (ret == 51)
						{
							uart_puts_P(" | [0x");
							uart_puthex_16byte(currentlocation);
							uart_puts_P("] [");
							itoa(currentlocation, buffer, 10);
							uart_puts(buffer);
							uart_puts_P("] (");
							itoa(mainloop,buffer,10);
							uart_puts(buffer);
							uart_puts_P(" - 0x");
							uart_puthex_byte(mainloop);
							uart_puts_P(")\n\r");
							ret=0;
						}
						currentlocation++;
						if(currentlocation > DEVICE_MAX)
						{
							break;
						}
					}
					_delay_ms(1000);
				}
				uart_puts_P("\n\r>> EVERY BYTE ON THE DEVICE HAS BEEN DUMPED!");
			}
			else if ( c == (unsigned char)'d')															/// [d] Dump entire contents of EEPROM in ASCII mode
			{
				location = DEVICE_MIN; //Start location
				currentlocation = 0;
				uart_puts_P("\n\rBEGIN> DUMP ENTIRE CONTENTS OF EEPROM - ASCII MODE @ 51b per line \n\rOUT>\n\r");
				for ( mainloop = 0; mainloop < 129; mainloop++ ) {
					location = (255*mainloop);
					//------- READ LOOP -------------//
					DeviceID &= ~(1<<0);
					i2c_start_wait(DeviceID);
					i2c_write((location >> 8));
					i2c_write(location);
					DeviceID |= (1<<0);
					i2c_rep_start(DeviceID);

					for ( i = 0; i < 255; i++ ) {
						getbyte[i] = i2c_readAck();
					}

					i2c_stop();

					//-------- OUTPUT LOOP ----------//

					ret = 0;

					for ( i = 0; i < 255; i++ )
					{
						ret++;
						uart_puts_P(" ");
						uart_putc(getbyte[i]);
						getbyte[i] = 0;
						if (ret == 51)
						{
							uart_puts_P(" | [0x");
							uart_puthex_16byte(currentlocation);
							uart_puts_P("] [");
							itoa(currentlocation, buffer, 10);
							uart_puts(buffer);
							uart_puts_P("] (");
							itoa(mainloop,buffer,10);
							uart_puts(buffer);
							uart_puts_P(" - 0x");
							uart_puthex_byte(mainloop);
							uart_puts_P(")\n\r");
							ret=0;
						}
						currentlocation++;
						if(currentlocation > DEVICE_MAX)
						{
							break;
						}
					}
					_delay_ms(1000);
				}
				uart_puts_P("\n\r>> EVERY BYTE ON THE DEVICE HAS BEEN DUMPED!");
			}
			else if ( c == (unsigned char)'o')															// [f] Fill specific sections of EEPROM with data
			{
				uart_puts_P("\n\ro> Input new Ident.");
				do{
					getbyte[0] = uart_getc();
				} while (getbyte[0] == 0);
				uart_puts_P("\n\ro> Changing Device Identification Address..");
				uart_puts_P("\n\ro>   - OLD IDENT ADDRESS: 0x");
				uart_puthex_byte(DeviceID);
				DeviceID = getbyte[0];
				uart_puts_P("\n\ro>   - NEW IDENT ADDRESS: 0x");
				uart_puthex_byte(DeviceID);
			}
			else if ( c == (unsigned char)'c')															// [f] Fill specific sections of EEPROM with data
			{
				uart_puts_P("\n\rc> Clear after command?");
				do{
					getbyte[0] = uart_getc();
				} while (getbyte[0] == 0);
				uart_puts_P("\n\rc> Changing C.A.C. Option...");
				uart_puts_P("\n\rc>   - PREVIOUS: ");
				if(o_ClearCmds) { uart_puts_P("TRUE"); } else { uart_puts_P("FALSE"); }
				o_ClearCmds = (getbyte[0]-48);
				uart_puts_P("\n\rc>   -  CURRENT: ");
				if(o_ClearCmds) { uart_puts_P("TRUE"); } else { uart_puts_P("FALSE"); }
			}
			else if ( c == (unsigned char)'R')															// [f] Fill specific sections of EEPROM with data
			{
				do{
					getbyte[4] = uart_getc();
				} while (getbyte[4] != 0x73);

				do{
					getbyte[4] = uart_getc();
				} while (getbyte[4] == 0);

				do{
					getbyte[3] = uart_getc();
				} while (getbyte[3] == 0);

				do{
					getbyte[0] = uart_getc();
				} while (getbyte[0] == 0);

				do{
					getbyte[1] = uart_getc();
				} while (getbyte[1] == 0);

				do{
					getbyte[2] = uart_getc();
				} while (getbyte[2] == 0);

				dub = (((getbyte[4]-48)*10000)+((getbyte[3]-48)*1000)+((getbyte[0]-48)*100)+((getbyte[1]-48)*10)+(getbyte[2]-48));

				do{
					getbyte[0] = uart_getc();
				} while (getbyte[0] != 0x65);

				do{
					getbyte[4] = uart_getc();
				} while (getbyte[4] == 0);

				do{
					getbyte[3] = uart_getc();
				} while (getbyte[3] == 0);

				do{
					getbyte[0] = uart_getc();
				} while (getbyte[0] == 0);

				do{
					getbyte[1] = uart_getc();
				} while (getbyte[1] == 0);

				do{
					getbyte[2] = uart_getc();
				} while (getbyte[2] == 0);

				i2 = (((getbyte[4]-48)*10000)+((getbyte[3]-48)*1000)+((getbyte[0]-48)*100)+((getbyte[1]-48)*10)+(getbyte[2]-48));

				do{
					getbyte[1] = uart_getc();
				} while (getbyte[1] != 0x6D);

				do{
					getbyte[2] = uart_getc();
				} while (getbyte[2] == 0);

				ret = ((getbyte[2])-48);

				if (i2>DEVICE_MAX)
				{
					uart_puts_P("\n\r!> Ending is over the max. Ending is now set to max...\n\r");
					i2=DEVICE_MAX;
				}

				uart_puts_P("> Sending EEPROM Read Command >\n\r ");
				eeprom_output_section(dub,i2, ret);

			}
			else if ( c == (unsigned char)'A')
			{
				uart_puts_P("\n\rA> [ABOUT]\n\r\n\rA> TITLE: 2WIRE Big-Boss (Like master but bigger!)\n\rA> AUTHOR: Brent C Reamer (BrentBXR on AVRFreaks Forum)\n\tA>VERSION: ");
				_delay_ms(50);
				uart_puts(bb_ver);
				uart_puts_P("\n\rA> DESCRIPTION: This program was created when I was in aww at the bus pirate. I didnt yet own one but wanted to be able to control");
				uart_puts_P("\n\rA>              devices like it. So i made this but it only has 2WIRE serial (12c compat.)\n\rA>\n\rA> Thank you for trying it out!   -BR");
				_delay_ms(100);
				uart_puts_P("\n\rA>\n\rA>    P.S: I now own a real open-source bus-pirate and its the best development/hacking tool ever created! (this project has nothing on the BP). Check out danger proto's to check it out! They also");
				uart_puts_P("\n\rA> sell an awesome (cheap) open-source usb logic analyzer. Everyone needs these 2 tools. I cant wait to see whats next.");
			}
			else if ( c == (unsigned char)'?')
			{
				uart_puts_P("\n\r?> [HELP] Listing Available Commands:\n\r\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [?]  \t - Displays this (?)help screen. \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [A]  \t - Displays the (A)BOUT information. \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [c]  \t - Allows you to enable(1) or disable(0) the (c)lear-after-aommand option (c1 or c0) (in br@ys set 4 as clear char to use this) \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [i]  \t - This (i)nitilizes the 2wire serial bus for communication as the master and gets acknowledge from slave. \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [o]  \t - Allows you (o)verwrite the device to address; Usage: o<0x##> where XX = device address (eg o$AE in br@ys) \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [D]  \t - (D)umps entire contents of EEPROM in HEX format. Use rarly and with caution. \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [d]  \t - (d)umps entire contents of EEPROM in ASCII format. Use rarly and with caution. \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [R]  \t - (R)eads a requested section of EEPROM in either HEX or ASCII mode. Usage: \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t   - Usage: R s##### e##### m#.    (Note: You must send in this order, you cannot put e before s and so on.)  \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t    \tWhere:\t s##### = Starting address in decimal format; must be 5 digits. (eg s00010 = Start at 10).\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t    \t      \t e##### = Ending address in decimal format; must be 5 digits and after starting address. (eg e00255 = End at 255).\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t    \t      \t m#     = Mode. 1 = HEX / 0 = ASCII; must be 1 or 0. (eg m1 = dump in hex mode.)\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t   - Example: (in br@ys Terminal) \"R s00010 e00265 m1\" would dump 255 bytes starting at d10 in hex mode.\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t [S]  \t - (S)ends bytes to the addressed device (address using 'o'). This will first address the device and send bytes to the bus \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t   - Usage: S[## ## ... ##].    (Note: You can send up to 100 bytes, always open with [ and end with ]. ALWAYS! include spaces between bytes.)  \n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t    \tWhere:\t ##      = Byte to send. (In br@ys it would be $AE to send 0xAE. Do not send in decimal format).\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t    \t      \t [       = This sends the serial start communication command and addresses the device. THIS ALWAYS NEEDS TO BE INCLUDED.\n\r");
				_delay_ms(50);

				uart_puts_P("?>  \t      \t    \t      \t ]       = This sends the serial stop communication command to the bus. This should always be included.\n\r");
				_delay_ms(50);

				uart_puts_P("?>\n\r?> Some commands may have been left out due to time constraints. View AVRFreaks forum project page for most up-to-date list of commands. \n\r");
				_delay_ms(50);
			}
			else
			{
				uart_puts_P("\n\r!> Unknown command");
			}
			uart_puts_P("\n\r\n\r>> Command Complete.\n\r\n\r");
			uart_puts_P("\n\r>> Awaiting Command.\n\r");
		}
    }
    return 0;
}
